/*-------------------------------------------------------------------------
 *
 * genam.h
 *	  POSTGRES 泛型索引访问方法的定义
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/access/genam.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef GENAM_H
#define GENAM_H

#include "access/sdir.h"
#include "access/skey.h"
#include "nodes/tidbitmap.h"
#include "storage/lockdefs.h"
#include "utils/relcache.h"
#include "utils/snapshot.h"

/* 我们不希望这个文件依赖 execnodes.h。 */
struct IndexInfo;

/*
 * ambuild 返回的统计信息结构
 */
typedef struct IndexBuildResult
{
	double		heap_tuples;	/* 在父表中看到的元组数量 */
	double		index_tuples;	/* 插入到索引中的元组数量 */
} IndexBuildResult;

/*
 * 传递给 ambulkdelete 和 amvacuumcleanup 的输入参数结构
 *
 * num_heap_tuples 仅在 estimated_count 为 false 时准确；
 * 否则它只是一个估计（目前，该估计是
 * 关系的 pg_class.reltuples 字段的先前值，因此它可以
 * 甚至是 -1）。在 ambulkdelete 期间，它始终只是一个估计。
 */
typedef struct IndexVacuumInfo
{
	Relation	index;			/* 正在清理的索引 */
	bool		analyze_only;	/* ANALYZE（没有实际的清理） */
	bool		report_progress;	/* 发出 progress.h 状态报告 */
	bool		estimated_count;	/* num_heap_tuples 是一个估计 */
	int			message_level;	/* 进度消息的ereport级别 */
	double		num_heap_tuples;	/* 堆中剩余的元组 */
	BufferAccessStrategy strategy;	/* 读取的访问策略 */
} IndexVacuumInfo;

/*
 * ambulkdelete 和 amvacuumcleanup 返回的统计信息结构
 *
 * 这个结构通常由第一次 ambulkdelete 调用分配，然后
 * 通过随后的调用传递到 amvacuumcleanup；然而，
 * 在没有进行任何 ambulkdelete 调用的情况下（因为没有
 * 需要删除的元组），amvacuumcleanup 必须准备自行分配它。
 * 注意，一个索引 AM 可以选择返回一个更大的结构，
 * 其中这个结构仅是第一个字段；这为 ambulkdelete
 * 与 amvacuumcleanup 之间传递额外的私有数据提供了一种方式。
 *
 * 注意：pages_newly_deleted 是当前清理操作中被删除的
 * 索引页面数量。pages_deleted 和 pages_free
 * 指的是索引文件中的空闲空间。
 *
 * 注意：一些索引 AM 可能通过引用 num_heap_tuples 来
 * 计算 num_index_tuples，在这种情况下，它们应该从
 * IndexVacuumInfo 中复制 estimated_count 字段。
 */
typedef struct IndexBulkDeleteResult
{
	BlockNumber num_pages;		/* 索引中剩余的页面 */
	bool		estimated_count;	/* num_index_tuples 是一个估计值 */
	double		num_index_tuples;	/* 剩余的元组 */
	double		tuples_removed; /* 在清理操作中移除的数量 */
	BlockNumber pages_newly_deleted;	/* 我们标记为已删除的页面数量  */
	BlockNumber pages_deleted;	/* 标记为已删除的页面数量（可能是我们） */
	BlockNumber pages_free;		/* 可供重用的页面数量 */
} IndexBulkDeleteResult;

/* 回调函数的typedef，用于判断元组是否可批量删除 */
typedef bool (*IndexBulkDeleteCallback) (ItemPointer itemptr, void *state);

/* struct 定义出现在 relscan.h 中 */
typedef struct IndexScanDescData *IndexScanDesc;
typedef struct SysScanDescData *SysScanDesc;

typedef struct ParallelIndexScanDescData *ParallelIndexScanDesc;

/*
 * 枚举，指定在 index_insert() 中执行的唯一性检查类型。
 *
 * UNIQUE_CHECK_YES 是传统的 Postgres 立即检查，可能
 * 会阻塞以查看是否有冲突事务提交。
 *
 * 对于可延迟的唯一约束，插入时指定 UNIQUE_CHECK_PARTIAL。
 * 索引 AM 应该测试元组是否唯一，但如果元组
 * 看起来不唯一，则不应抛出错误、阻塞或阻止插入。
 * 我们将在约束执行时重新检查。AM 必须在元组
 * 已知唯一时返回 true，在可能非唯一时返回 false。
 * 在 "true" 的情况下，可以安全地省略后续的重新检查。
 *
 * 当需要重新检查延迟约束时，以 UNIQUE_CHECK_EXISTING
 * 进行伪插入调用。在这种情况下，元组已经存在于
 * 索引中，因此不应再次插入。相反，只需检查
 * 是否存在冲突的活动元组（可能需要阻塞）。
 */
typedef enum IndexUniqueCheck
{
	UNIQUE_CHECK_NO,			/* 不执行任何唯一性检查 */
	UNIQUE_CHECK_YES,			/* 在插入时强制唯一性 */
	UNIQUE_CHECK_PARTIAL,		/* 测试唯一性，但不报错 */
	UNIQUE_CHECK_EXISTING		/* 检查现有元组是否唯一 */
} IndexUniqueCheck;


/* 可空的 "ORDER BY col op const" 距离 */
typedef struct IndexOrderByDistance
{
	double		value;
	bool		isnull;
} IndexOrderByDistance;

/*
 * 通用索引接口例程（在 indexam.c 中）
 */

/*
 * IndexScanIsValid
 *		当且仅当索引扫描有效时为真。
 */
#define IndexScanIsValid(scan) PointerIsValid(scan)

extern Relation index_open(Oid relationId, LOCKMODE lockmode);
extern Relation try_index_open(Oid relationId, LOCKMODE lockmode);
extern void index_close(Relation relation, LOCKMODE lockmode);

extern bool index_insert(Relation indexRelation,
						 Datum *values, bool *isnull,
						 ItemPointer heap_t_ctid,
						 Relation heapRelation,
						 IndexUniqueCheck checkUnique,
						 bool indexUnchanged,
						 struct IndexInfo *indexInfo);

extern IndexScanDesc index_beginscan(Relation heapRelation,
									 Relation indexRelation,
									 Snapshot snapshot,
									 int nkeys, int norderbys);
extern IndexScanDesc index_beginscan_bitmap(Relation indexRelation,
											Snapshot snapshot,
											int nkeys);
extern void index_rescan(IndexScanDesc scan,
						 ScanKey keys, int nkeys,
						 ScanKey orderbys, int norderbys);
extern void index_endscan(IndexScanDesc scan);
extern void index_markpos(IndexScanDesc scan);
extern void index_restrpos(IndexScanDesc scan);
extern Size index_parallelscan_estimate(Relation indexrel, Snapshot snapshot);
extern void index_parallelscan_initialize(Relation heaprel, Relation indexrel,
										  Snapshot snapshot, ParallelIndexScanDesc target);
extern void index_parallelrescan(IndexScanDesc scan);
extern IndexScanDesc index_beginscan_parallel(Relation heaprel,
											  Relation indexrel, int nkeys, int norderbys,
											  ParallelIndexScanDesc pscan);
extern ItemPointer index_getnext_tid(IndexScanDesc scan,
									 ScanDirection direction);
struct TupleTableSlot;
extern bool index_fetch_heap(IndexScanDesc scan, struct TupleTableSlot *slot);
extern bool index_getnext_slot(IndexScanDesc scan, ScanDirection direction,
							   struct TupleTableSlot *slot);
extern int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap);

extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
												IndexBulkDeleteResult *istat,
												IndexBulkDeleteCallback callback,
												void *callback_state);
extern IndexBulkDeleteResult *index_vacuum_cleanup(IndexVacuumInfo *info,
												   IndexBulkDeleteResult *istat);
extern bool index_can_return(Relation indexRelation, int attno);
extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
									uint16 procnum);
extern FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum,
								   uint16 procnum);
extern void index_store_float8_orderby_distances(IndexScanDesc scan,
												 Oid *orderByTypes,
												 IndexOrderByDistance *distances,
												 bool recheckOrderBy);
extern bytea *index_opclass_options(Relation relation, AttrNumber attnum,
									Datum attoptions, bool validate);


/*
 * 索引访问方法支持例程（在 genam.c 中）
 */
extern IndexScanDesc RelationGetIndexScan(Relation indexRelation,
										  int nkeys, int norderbys);
extern void IndexScanEnd(IndexScanDesc scan);
extern char *BuildIndexValueDescription(Relation indexRelation,
										Datum *values, bool *isnull);
extern TransactionId index_compute_xid_horizon_for_tuples(Relation irel,
														  Relation hrel,
														  Buffer ibuf,
														  OffsetNumber *itemnos,
														  int nitems);

/*
 * 访问系统目录的堆或索引（在 genam.c 中）
 */
extern SysScanDesc systable_beginscan(Relation heapRelation,
									  Oid indexId,
									  bool indexOK,
									  Snapshot snapshot,
									  int nkeys, ScanKey key);
extern HeapTuple systable_getnext(SysScanDesc sysscan);
extern bool systable_recheck_tuple(SysScanDesc sysscan, HeapTuple tup);
extern void systable_endscan(SysScanDesc sysscan);
extern SysScanDesc systable_beginscan_ordered(Relation heapRelation,
											  Relation indexRelation,
											  Snapshot snapshot,
											  int nkeys, ScanKey key);
extern HeapTuple systable_getnext_ordered(SysScanDesc sysscan,
										  ScanDirection direction);
extern void systable_endscan_ordered(SysScanDesc sysscan);
extern void systable_inplace_update_begin(Relation relation,
										  Oid indexId,
										  bool indexOK,
										  Snapshot snapshot,
										  int nkeys, const ScanKeyData *key,
										  HeapTuple *oldtupcopy,
										  void **state);
extern void systable_inplace_update_finish(void *state, HeapTuple tuple);
extern void systable_inplace_update_cancel(void *state);

#endif							/* GENAM_H */
